#include <Lucnx/interrupt.h>
#include <Lucnx/debug.h>
#include <Lucnx/types.h>
#include <Lucnx/debug.h>
#include <Lucnx/global.h>
#include <Lucnx/printk.h>
#include <Lucnx/task.h>
#include <Lucnx/stdlib.h>
#include <Lucnx/console.h>
#include <Lucnx/io.h>

#define PIC_M_CTRL 0x20 
#define PIC_M_DATA 0x21 
#define PIC_S_CTRL 0xA0 
#define PIC_S_DATA 0xA1 

static char *messages[] = {
        "#DE Divide Error\0",
        "#DB RESERVED\0",
        "--  NMI Interrupt\0",
        "#BP Breakpoint\0",
        "#OF Overflow\0",
        "#BR BOUND Range Exceeded\0",
        "#UD Invalid Opcode (Undefined Opcode)\0",
        "#NM Device Not Available (No Math Coprocessor)\0",
        "#DF Double Fault\0",
        "    Coprocessor Segment Overrun (reserved)\0",
        "#TS Invalid TSS\0",
        "#NP Segment Not Present\0",
        "#SS Stack-Segment Fault\0",
        "#GP General Protection\0",
        "#PF Page Fault\0",
        "--  (Intel reserved. Do not use.)\0",
        "#MF x87 FPU Floating-Point Error (Math Fault)\0",
        "#AC Alignment Check\0",
        "#MC Machine Check\0",
        "#XF SIMD Floating-Point Exception\0",
        "#VE Virtualization Exception\0",
        "#CP Control Protection Exception\0",
};

// 中断门
typedef struct gate_t
{
    u16 offset_low;
    u16 selector;
    u8 dcount;
    u8 type : 4;
    u8 segment : 1;
    u8 DPL : 2;
    u8 P : 1;
    u16 offset_high;
}_packed gate_t;

extern void *syscall_handler(); // 系统调用
extern void *handler_entry_table[0x30];
void *handler_table[0x30];
gate_t idt[NR_HANDLERS];

static void gate_init(gate_t *p_gate, void *offset, u8 dpl)
{
    p_gate->offset_low = (u32)offset & 0x0000FFFF;
    p_gate->dcount = 0; 
    p_gate->type = 0b1110; 
    p_gate->selector = (1 << 3); 
    p_gate->DPL = dpl;
    p_gate->segment = 0;
    p_gate->P = 1; 
    p_gate->offset_high = ((u32)offset & 0xFFFF0000) >> 16;
}

void error_handler(u32 vector, u32 edi, u32 esi, u32 ebp, u32 esp_dummy, u32 ebx, u32 edx, u32 ecx, u32 eax, \
                    u32 gs, u32 fs, u32 es, u32 ds, u32 vector0, u32 magic, u32 eip, u32 cs, u32 eflags, u32 esp, u32 ss)
{
    task_t *task = running_task();
    // printk("ERROR %s\n", messages[vector]);

    printk("eip:%x\n", eip);
    printk("eax:%x\n", eax);
    printk("ebx:%x\n", ebx);
    printk("ecx:%x\n", ecx);
    printk("edx:%x\n", edx);
    printk("edi:%x\n", edi);
    printk("esi:%x\n", esi);
    printk("ebp:%x\n", ebp);
    printk("esp_dummy:%x\n", esp_dummy);
    printk("esp:%x\n\n", esp);
    printk("ds:%x\n", ds & 0xFFFF);
    printk("es:%x\n", es & 0xFFFF);
    printk("fs:%x\n", fs & 0xFFFF);
    printk("gs:%x\n", gs & 0xFFFF);
    printk("ss:%x\n", ss & 0xFFFF);
    printk("cs:%x\n", cs & 0xFFFF);

    if (vector == 0x0e) 
    {
        printk("cr2:%x\n", get_cr2());
    }

    if (task->mode == 2)
    {
        sys_exit(); // 错误进程退出
    }

    hang(); 
}

// 初始化 8259A
void pic_init()
{
    outb(PIC_M_CTRL, 0b00010001);
    outb(PIC_M_DATA, 0x20);
    outb(PIC_M_DATA, 0b100);
    outb(PIC_M_DATA, 0b00000001);

    outb(PIC_S_CTRL, 0b00010001);
    outb(PIC_S_DATA, 0x28);
    outb(PIC_S_DATA, 2);
    outb(PIC_S_DATA, 0b00000001);

    outb(PIC_M_DATA, 0xFF);
    outb(PIC_S_DATA, 0xFF);
}

// 设置 irq
void set_pic_irq(u8 vector, bool state)
{
    assert(vector < 0x30 && vector > 0x19)

    u8 irq_idx = vector - 0x20;
    u16 port;

    if (irq_idx < 8)
    {
        port = PIC_M_DATA;
    }
    else
    {
        port = PIC_S_DATA;
        irq_idx -= 8;
    }
    
    if (state)
    {
        outb(port, inb(port) & ~(1 << irq_idx));
        return;
    }
    outb(port, inb(port) | (1 << irq_idx));
}

void default_handler(u8 vector)
{
    printk("irq%d interrupt\n", vector - 0x20);
}

void interrupt_init()
{
    pic_init();

    for (size_t i = 0; i < 0x30; i++)
    {
        gate_init(&idt[i], handler_entry_table[i], 0);
    }

    for (size_t i = 0; i < 20; i++)
    {
        register_handler(i, error_handler);
    }

    for (size_t i = 0x20; i < 0x30; i++)
    {
        register_handler(i, default_handler);
    }

    gate_init(&idt[0x80], syscall_handler, 3);

    u64 idt_ptr = (u64)(u32)idt << 16 | sizeof(idt) - 1;
    asm volatile("lidt %0" :: "g"(idt_ptr)); // 加载 idt
}

void register_handler(int vector, void  *handler)
{
    handler_table[vector] = handler;
}

// 获取 eflags 寄存器
static u32 get_eflags()
{
    asm volatile("pushfl\n"
                "popl %eax\n");
}

bool get_interrupt_state()
{
    u32 eflags = get_eflags();
    return eflags & 0x200;
}

// 设置中断状态, 并返回之前的状态
bool set_interrupt_state(bool state)
{
    bool old_state = get_interrupt_state();
    if (state)
    {
        asm volatile("sti\n");
    }
    else
    {
        asm volatile("cli\n");
    }
    return old_state;
}